Merge remote-tracking branch 'huginn/master' into omniauth

Dominik Sander %!s(int64=9) %!d(string=hace) años
padre
commit
e57b806d18

+ 1 - 0
.travis.yml

@@ -1,4 +1,5 @@
1 1
 language: ruby
2
+cache: bundler
2 3
 bundler_args: --without development production
3 4
 env:
4 5
   - APP_SECRET_TOKEN=b2724973fd81c2f4ac0f92ac48eb3f0152c4a11824c122bcf783419a4c51d8b9bba81c8ba6a66c7de599677c7f486242cf819775c433908e77c739c5c8ae118d TWITTER_OAUTH_KEY=twitteroauthkey TWITTER_OAUTH_SECRET=twitteroauthsecret

+ 76 - 0
app/models/agents/change_detector_agent.rb

@@ -0,0 +1,76 @@
1
+module Agents
2
+  class ChangeDetectorAgent < Agent
3
+    cannot_be_scheduled!
4
+
5
+    description <<-MD
6
+      The ChangeDetectorAgent receives a stream of events and emits a new event when a property of the received event changes.
7
+
8
+      `property` specifies the property to be watched.
9
+
10
+      `expected_update_period_in_days` is used to determine if the Agent is working.
11
+
12
+      The resulting event will be a copy of the received event.
13
+    MD
14
+
15
+    event_description <<-MD
16
+    This will change based on the source event. If you were event from the ShellCommandAgent, your outbound event might look like:
17
+
18
+      {
19
+        'command' => 'pwd',
20
+        'path' => '/home/Huginn',
21
+        'exit_status' => '0',
22
+        'errors' => '',
23
+        'output' => '/home/Huginn'
24
+      }
25
+    MD
26
+
27
+    def default_options
28
+      {
29
+          'property' => '{{output}}',
30
+          'expected_update_period_in_days' => 1
31
+      }
32
+    end
33
+
34
+    def validate_options
35
+      unless options['property'].present? && options['expected_update_period_in_days'].present?
36
+        errors.add(:base, "The property and expected_update_period_in_days fields are all required.")
37
+      end
38
+    end
39
+
40
+    def working?
41
+      event_created_within?(interpolated['expected_update_period_in_days']) && !recent_error_logs?
42
+    end
43
+
44
+    def receive(incoming_events)
45
+      incoming_events.each do |event|
46
+        handle(interpolated(event), event)
47
+      end
48
+    end
49
+
50
+    private
51
+
52
+    def handle(opts, event = nil)
53
+      property = opts['property']
54
+      if has_changed?(property)
55
+        created_event = create_event :payload => event.payload
56
+
57
+        log("Propagating new event as property has changed to #{property} from #{last_property}", :outbound_event => created_event, :inbound_event => event )
58
+        update_memory(property)
59
+      else
60
+        log("Not propagating as incoming event has not changed from #{last_property}.", :inbound_event => event )
61
+      end
62
+    end
63
+
64
+    def has_changed?(property)
65
+      property != last_property
66
+    end
67
+
68
+    def last_property
69
+      self.memory['last_property']
70
+    end
71
+
72
+    def update_memory(property)
73
+      self.memory['last_property'] = property
74
+    end
75
+  end
76
+end

+ 17 - 16
app/views/devise/passwords/new.html.erb

@@ -1,27 +1,28 @@
1
-<div class='container'>
2
-  <div class='row'>
3
-    <div class='span8 offset2'>
4
-      <div class='well'>
5
-        <h2>Forgot your password?</h2>
1
+<div class='row'>
2
+  <div class='col-md-6 col-md-offset-3'>
3
+    <div class='well'>
4
+      <h2>Forgot your password?</h2>
6 5
 
7
-        <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, :class => 'form-horizontal' }) do |f| %>
8
-          <%= devise_error_messages! %>
6
+      <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, :class => 'form-horizontal' }) do |f| %>
7
+        <%= devise_error_messages! %>
9 8
 
10
-          <div class="control-group">
11
-            <%= f.label :login, :class => 'control-label' %>
12
-            <div class="controls">
13
-              <%= f.text_field :login, :class => 'span4' %>
14
-            </div>
9
+        <div class="form-group">
10
+          <%= f.label :login, :class => 'col-md-2 col-md-offset-2 control-label' %>
11
+          <div class="col-md-6">
12
+            <%= f.text_field :login, :class => 'form-control' %>
15 13
           </div>
14
+        </div>
16 15
 
17
-          <div class='form-actions'>
16
+        <div class="form-group">
17
+          <div class="col-md-offset-4 col-md-10">
18 18
             <%= f.submit "Send me reset password instructions", :class => "btn btn-primary" %>
19 19
           </div>
20
-        <% end %>
20
+        </div>
21
+      <% end %>
21 22
 
22
-        <%= render "devise/shared/links" %>
23
+      <hr>
23 24
 
24
-      </div>
25
+      <%= render "devise/shared/links" %>
25 26
     </div>
26 27
   </div>
27 28
 </div>

+ 24 - 10
app/views/devise/unlocks/new.html.erb

@@ -1,14 +1,28 @@
1
-<h2>Resend unlock instructions</h2>
1
+<div class='row'>
2
+  <div class='col-md-6 col-md-offset-3'>
3
+    <div class='well'>
4
+      <h2>Resend unlock instructions</h2>
2 5
 
3
-<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
4
-  <%= devise_error_messages! %>
6
+      <%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post, :class => 'form-horizontal' }) do |f| %>
7
+        <%= devise_error_messages! %>
5 8
 
6
-  <div>
7
-    <%= f.label :email %>
8
-    <%= f.email_field :email %>
9
-  </div>
9
+        <div class="form-group">
10
+          <%= f.label :email, :class => 'col-md-2 col-md-offset-2 control-label' %>
11
+          <div class="col-md-6">
12
+            <%= f.text_field :email, :class => 'form-control' %>
13
+          </div>
14
+        </div>
15
+
16
+        <div class="form-group">
17
+          <div class="col-md-offset-4 col-md-10">
18
+            <%= f.submit "Resend unlock instructions", :class => "btn btn-primary" %>
19
+          </div>
20
+        </div>
21
+      <% end %>
10 22
 
11
-  <div><%= f.submit "Resend unlock instructions" %></div>
12
-<% end %>
23
+      <hr>
13 24
 
14
-<%= render "devise/shared/links" %>
25
+      <%= render "devise/shared/links" %>
26
+    </div>
27
+  </div>
28
+</div>

+ 98 - 0
spec/models/agents/change_detector_agent_spec.rb

@@ -0,0 +1,98 @@
1
+require 'spec_helper'
2
+
3
+describe Agents::ChangeDetectorAgent do
4
+  def create_event(output=nil)
5
+    event = Event.new
6
+    event.agent = agents(:jane_weather_agent)
7
+    event.payload = {
8
+      :command => 'some-command',
9
+      :output => output
10
+    }
11
+    event.save!
12
+
13
+    event
14
+  end
15
+
16
+  before do
17
+    @valid_params = {
18
+        :property  => "{{output}}",
19
+        :expected_update_period_in_days => "1",
20
+      }
21
+
22
+    @checker = Agents::ChangeDetectorAgent.new(:name => "somename", :options => @valid_params)
23
+    @checker.user = users(:jane)
24
+    @checker.save!
25
+  end
26
+
27
+  describe "validation" do
28
+    before do
29
+      @checker.should be_valid
30
+    end
31
+
32
+    it "should validate presence of property" do
33
+      @checker.options[:property] = nil
34
+      @checker.should_not be_valid
35
+    end
36
+
37
+    it "should validate presence of property" do
38
+      @checker.options[:expected_update_period_in_days] = nil
39
+      @checker.should_not be_valid
40
+    end
41
+  end
42
+
43
+  describe "#working?" do
44
+    before :each do
45
+      # Need to create an event otherwise event_created_within? returns nil
46
+      event = create_event
47
+      @checker.receive([event])
48
+    end
49
+
50
+    it "is when event created within :expected_update_period_in_days" do
51
+      @checker.options[:expected_update_period_in_days] = 2
52
+      @checker.should be_working
53
+    end
54
+
55
+    it "isnt when event created outside :expected_update_period_in_days" do
56
+      @checker.options[:expected_update_period_in_days] = 2
57
+
58
+      time_travel_to 2.days.from_now do
59
+          @checker.should_not be_working
60
+      end
61
+    end
62
+  end
63
+
64
+  describe "#receive" do
65
+    before :each do
66
+      @event = create_event("2014-07-01")
67
+    end
68
+
69
+    it "creates events when memory is empty" do
70
+      @event.payload[:output] = "2014-07-01"
71
+      expect {
72
+        @checker.receive([@event])
73
+      }.to change(Event, :count).by(1)
74
+      Event.last.payload[:command].should == @event.payload[:command]
75
+      Event.last.payload[:output].should == @event.payload[:output]
76
+    end
77
+
78
+    it "creates events when new event changed" do
79
+      @event.payload[:output] = "2014-07-01"
80
+      @checker.receive([@event])
81
+
82
+      event = create_event("2014-08-01")
83
+
84
+      expect {
85
+        @checker.receive([event])
86
+      }.to change(Event, :count).by(1)
87
+    end
88
+
89
+    it "does not create event when no change" do
90
+      @event.payload[:output] = "2014-07-01"
91
+      @checker.receive([@event])
92
+
93
+      expect {
94
+        @checker.receive([@event])
95
+      }.to change(Event, :count).by(0)
96
+    end
97
+  end
98
+end

+ 2 - 2
spec/models/event_spec.rb

@@ -85,7 +85,7 @@ describe EventDrop do
85 85
   before do
86 86
     @event = Event.new
87 87
     @event.agent = agents(:jane_weather_agent)
88
-    @event.created_at = Time.at(1400000000)
88
+    @event.created_at = Time.now
89 89
     @event.payload = {
90 90
       'title' => 'some title',
91 91
       'url' => 'http://some.site.example.org/',
@@ -115,6 +115,6 @@ describe EventDrop do
115 115
 
116 116
   it 'should have created_at' do
117 117
     t = '{{created_at | date:"%FT%T%z" }}'
118
-    interpolate(t, @event).should eq('2014-05-13T09:53:20-0700')
118
+    interpolate(t, @event).should eq(@event.created_at.strftime("%FT%T%z"))
119 119
   end
120 120
 end

+ 3 - 1
spec/support/shared_examples/liquid_interpolatable.rb

@@ -9,7 +9,9 @@ shared_examples_for LiquidInterpolatable do
9 9
       "escape" => "This should be {{hello_world | uri_escape}}"
10 10
     }
11 11
 
12
-    @checker = described_class.new(:name => "somename", :options => @valid_params)
12
+    @checker = new_instance
13
+    @checker.name = "somename"
14
+    @checker.options = @valid_params
13 15
     @checker.user = users(:jane)
14 16
 
15 17
     @event = Event.new